package org.jetbrains.kotlin.library

import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.MetadataVersion

data class KotlinLibraryVersioning(
    val compilerVersion: String?,
    val abiVersion: KotlinAbiVersion?,
    val metadataVersion: MetadataVersion?,
    val irSignatureVersions: Set<KotlinIrSignatureVersion> = KotlinIrSignatureVersion.CURRENTLY_SUPPORTED_VERSIONS,
) {
    init {
        require(irSignatureVersions.isNotEmpty()) {
            "Signature versions must not be empty!"
        }
    }
}

fun Properties.writeKonanLibraryVersioning(versions: KotlinLibraryVersioning) {
    versions.abiVersion?.let { this.setProperty(KLIB_PROPERTY_ABI_VERSION, it.toString()) }
    versions.compilerVersion?.let { this.setProperty(KLIB_PROPERTY_COMPILER_VERSION, it) }
    versions.metadataVersion?.let { this.setProperty(KLIB_PROPERTY_METADATA_VERSION, it.toString()) }
    this.setProperty(KLIB_PROPERTY_IR_SIGNATURE_VERSIONS, versions.irSignatureVersions.toManifestValue())
}

fun Properties.readKonanLibraryVersioning(): KotlinLibraryVersioning {
    val abiVersion = this.getProperty(KLIB_PROPERTY_ABI_VERSION)?.parseKotlinAbiVersion()
    val compilerVersion = this.getProperty(KLIB_PROPERTY_COMPILER_VERSION)
    val metadataVersion = this.getProperty(KLIB_PROPERTY_METADATA_VERSION)?.let {
        BinaryVersion.parseVersionArray(it)?.let { binaryVersion -> MetadataVersion(*binaryVersion) }
    }

    // If there is no such property in the manifest, it means that the manifest was generated by an older version of the compiler,
    // meaning that it only contains v1 signatures.
    val irSignatureVersions = this.getProperty(KLIB_PROPERTY_IR_SIGNATURE_VERSIONS)?.parseIrSignatureVersions()
        ?.also { check(it.isNotEmpty()) { "Malformed manifest: Empty set of IR signature versions" } }
        ?: setOf(KotlinIrSignatureVersion.V1)

    return KotlinLibraryVersioning(
        abiVersion = abiVersion,
        compilerVersion = compilerVersion,
        metadataVersion = metadataVersion,
        irSignatureVersions = irSignatureVersions,
    )
}
